﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Reflection;

namespace JackyCode.Mock
{
    public class MethodData
    {
        public MethodInfo MethodInfo { get; set; }

        public ReadOnlyCollection<ArgumentDetail> ArgumentDetails { get; set; }

        public MethodData(IList<ArgumentDetail> argumentDetails,MethodInfo methodInfo)
        {
            ArgumentDetails = new ReadOnlyCollection<ArgumentDetail>(argumentDetails);
            this.MethodInfo = methodInfo;
        }

        public MethodData(MethodInfo methodInfo) : this(new List<ArgumentDetail>(), methodInfo) { }

        public MethodData(IList<object> arguments, MethodInfo methodInfo)
        {
            ArgumentDetails = new ReadOnlyCollection<ArgumentDetail>(GetArgDetails(arguments,methodInfo));
            this.MethodInfo = methodInfo;
        }

        private IList<ArgumentDetail> GetArgDetails(IList<object> arguments, MethodInfo methodInfo)
        {
            IList<ArgumentDetail> argDetails = new List<ArgumentDetail>();
            ParameterInfo[] parameterInfos = methodInfo.GetParameters();
            for (int index = 0; index < parameterInfos.Length; index++)
            {
                argDetails.Add
                (
                    new ArgumentDetail 
                    { 
                        IsNotOut = !parameterInfos[index].IsOut, 
                        Value = arguments[index] 
                    }
                );
            }
            return argDetails;
        }

        public override bool Equals(object obj)
        {
            if(!(obj is MethodData))
            {
                return false;
            }

            MethodData cmpMethodData = (MethodData)obj;
            return IsMathMethodInfo(cmpMethodData)&& IsMathAllEqualCondition(cmpMethodData);

        }

        public override int GetHashCode()
        {
            return this.MethodInfo.GetHashCode();
        }

        private bool IsMathMethodInfo(MethodData cmpMethodData)
        {
            return cmpMethodData.MethodInfo.Equals(cmpMethodData.MethodInfo);
        }

        private bool IsMathAllEqualCondition(MethodData methodData)
        {
            for (int index = 0; index < ArgumentDetails.Count; index++)
            {
                ArgumentDetail curArgDetail = this.ArgumentDetails[index];
                ArgumentDetail cmpArgDetail = methodData.ArgumentDetails[index];
                if (curArgDetail.IsNotOut)
                {
                    if (!curArgDetail.Value.Equals(cmpArgDetail.Value))
                    {
                        return false;
                    }
                }
            }
            return true;
        }
    }

    public class ArgumentDetail
    {
        public object Value { get; set; }
        public bool IsNotOut { get; set; }
    }
}
